bl_info = {
	"name": "Easy Emit 2.0",
	"author": "Andreas Esau",
	"version": (2,0, 1),
	"blender": (2, 6, 7),
	"api": 56900,
	"location": "Properties > Particles",
	"description": "Particle System for the Blender Game Engine",
	"warning": "",
	"wiki_url": "",
	"tracker_url": "",
	"category": "Game Engine"}


import bpy
import math
import mathutils
import os
from bpy.app.handlers import persistent
import pickle
from bpy_extras.io_utils import ExportHelper
from bpy.props import StringProperty, BoolProperty, EnumProperty, FloatProperty, FloatVectorProperty, IntProperty, CollectionProperty, PointerProperty


class easyEmitUIAdd(bpy.types.Panel):
	bl_label = "easyEmit 2.0 - Generation"
	bl_space_type = 'PROPERTIES'
	bl_region_type = 'WINDOW'
	bl_context = "particle"
	COMPAT_ENGINES = {'BLENDER_GAME'}
	
	@classmethod
	def poll(cls, context):
		ob = context.active_object
		rd = context.scene.render
		if not ob.ee_emitter and not ob.ee_particle:
			return ob and ob.game and (rd.engine in cls.COMPAT_ENGINES)
	
	### draw function for all ui elements
	def draw(self, context):
		layout = self.layout
		split = self.layout.split()
		scene = bpy.data.scenes[0]
		ob = context.object
		sce = context.scene
		
		
		col = self.layout.column(align=True)
		col.operator("object.ee_generate_particle_system",text="Generate Particle System", icon='PARTICLES')
		
### draw class for the ui implementation
class easyEmitUISettings(bpy.types.Panel):
	bl_label = "easyEmit 2.0 - Settings"
	bl_space_type = 'PROPERTIES'
	bl_region_type = 'WINDOW'
	bl_context = "particle"
	COMPAT_ENGINES = {'BLENDER_GAME'}

	### update function that is executed for each property -> applies values for gameproperties
	def update_values(self, context):
		bpy.ops.object.ee_apply_values()
	
	def emitter_visible(self,context):
		context.active_object.hide_render = not context.active_object.ee_emitter_visible
	
	### particle properties
	bpy.types.Object.ee_refresh_rate = IntProperty(description="Refresh rate of the particle system. Lower values give nicer results but slower performance.",default=2,min=1,max=5,update=update_values)
	bpy.types.Object.ee_culling_on = BoolProperty(default=True,description="Emitter freezes if it is not camera view.",update=update_values)
	bpy.types.Object.ee_culling_radius = IntProperty(default=2,min=0,description="Set the range when emitter is freezed.",update=update_values)
	bpy.types.Object.ee_freeze_mode = EnumProperty(description="If set to Freeze, the Emitter will be freezed when not seen. Otherwise it will be paused.",items=(("Pause","Pause","Pause","PAUSE",1),("Freeze","Freeze","Freeze","FREEZE",0)),update=update_values)
	
	bpy.types.Object.ee_particle = BoolProperty(default=False)
	bpy.types.Object.ee_emitter = BoolProperty(default=False)
	
	bpy.types.Object.ee_name = StringProperty()
	bpy.types.Object.ee_amount = IntProperty(default=-1,min=-1,max=10000,description="Amount of particles that are emitted. -1 -> unlimited emission",update=update_values)
	bpy.types.Object.ee_halo = BoolProperty(default=True,update=update_values,description="If set, particles will always face to the camera.")
	
	bpy.types.Object.ee_gravity = FloatProperty(default=0.0,min=-1000.0,max=1000.0,description="Emitter Gravity Settings",update=update_values)
	
	
	bpy.types.Object.ee_emission_rate = IntProperty(default=60,min=1,max=300,description="Particle Emission Rate",update=update_values)
	bpy.types.Object.ee_lifetime = IntProperty(default=60,min=1,max=10000,description="Particle Lifetime",update=update_values)
	bpy.types.Object.ee_emission_range = FloatVectorProperty(default=(0.0,0.0,0.0),min=0.0,description="Emission Range",update=update_values,subtype="XYZ")
	bpy.types.Object.ee_emission_angle = FloatVectorProperty(default=(math.radians(30),math.radians(30)),min=0.0,max=math.radians(360),description="Emission Angle",size=2,precision=0,update=update_values,subtype="EULER")
	bpy.types.Object.ee_random_movement = FloatProperty(default=0.0,min=0.0,max=math.radians(3),description="Random Rotation Movement for each Particle",update=update_values,subtype="ANGLE")
	bpy.types.Object.ee_random_speed = FloatProperty(default=0.0,min=0.0,max=1.0,description="Random Speed for each Particle",update=update_values)
	bpy.types.Object.ee_rotation = FloatProperty(default=0.0,min=0.0,max=math.radians(24),description="Rotation for single Particle",subtype="ANGLE",update=update_values,precision=3)
	bpy.types.Object.ee_random_orientation= BoolProperty(default=True,description="Random Orientation on birth",update=update_values)
	bpy.types.Object.ee_explode = BoolProperty(default=False,description="Particles emit new Emitter on death",update=update_values)
	bpy.types.Object.ee_explode_emitter = StringProperty(default="Emitter Name",description="Emitter that is emitted on Particle death. Emitter has to be on separate layer.",update=update_values)
	bpy.types.Object.ee_emitter_visible = BoolProperty(default=False,description="Set if the emitter is visible ingame",update=emitter_visible)
	
	
	
	def update_emitter_list(self,context):
		ob = context.active_object
		ob.ee_explode_emitter = ob.ee_explode_emitter_enum
	
	def emitter_list(self,context):
		EMITTERLIST = []
		i = 0
		for object in context.scene.objects:
			if object.ee_emitter and object != context.active_object:
				EMITTERLIST.append((object.name,object.name,object.name,"OBJECT_DATAMODE",i))
				i+=1
		return EMITTERLIST
	bpy.types.Object.ee_explode_emitter_enum = EnumProperty(items=emitter_list,update=update_emitter_list)
	
	
	@classmethod
	def poll(cls, context):
		ob = context.active_object
		rd = context.scene.render
		if ob.ee_emitter:
			return ob and ob.game and (rd.engine in cls.COMPAT_ENGINES)
	
	### draw function for all ui elements
	def draw(self, context):
		layout = self.layout
		split = self.layout.split()
		scene = bpy.data.scenes[0]
		ob = context.object
		sce = context.scene
		
		# icon = layout.icon(bpy.data.images["ee_icon.png"])
		# row = self.layout.row(align=True)
		# row.label(text="EasyEmit",icon_value=icon)
		
		row = self.layout.row(align=True)
		row.prop(ob,"ee_refresh_rate",text="Refresh Rate")
		row = self.layout.row(align=True)
		row.prop(ob,"ee_culling_on",text="Frustum Culling")
		row.prop(ob,"ee_culling_radius",text="Radius")
		row.prop(ob,"ee_freeze_mode",text="",expand=True)
		row = self.layout.row()
		row.prop(ob,"ee_emitter_visible",text="Emitter Visible",icon='NONE',toggle=False)
		
		col = self.layout.column(align=True)
		col.template_list("UI_List_Proxy","dummy",ob, "ee_p_proxies", ob, "ee_p_colors_index",rows=1,maxrows=10,type='DEFAULT')
		col.operator("object.ee_add_new_pproxy",text="Add new Proxy", icon='ZOOMIN')
		
		row = self.layout.row()
		col = self.layout.column(align=False)
		col.prop(ob,"ee_amount",text="Emission Amount")
		col.prop(ob,"ee_emission_rate",text="Emission Rate")
		col.prop(ob,"ee_lifetime",text="Lifetime")
		col.prop(ob,"ee_gravity",text="Gravity")
		
		row = self.layout.row()
		row.column().prop(ob,"ee_emission_range",text="Emission Range")
		
		row = self.layout.row()
		row.column().prop(ob,"ee_emission_angle",text="Emission Angle",slider=True)
		
		row = self.layout.row()
		row.column().prop(ob,"ee_random_orientation",text="Random Orientation")
		row.column().prop(ob,"ee_halo",text="Halo")
		row = self.layout.row()
		row.column().prop(ob,"ee_rotation",text="Particle Rotation",slider=True)
		
		row = self.layout.row()
		row.label(text="Colors",icon="COLOR")
		
		col = self.layout.column(align=True)
		col.template_list("UI_List_Color","dummy",ob, "ee_p_colors", ob, "ee_p_colors_index",rows=1,maxrows=10,type='DEFAULT')
		op = col.operator("object.ee_add_new_pcolor",text="Add new Color", icon='ZOOMIN')
		op.color = mathutils.Vector(bpy.context.active_object.ee_p_colors[len(bpy.context.active_object.ee_p_colors)-1].color)
		op.frame = bpy.context.active_object.ee_p_colors[len(bpy.context.active_object.ee_p_colors)-1].frame+1
		
		row = self.layout.row()
		row = self.layout.row()
		row.label(text="Scaling",icon="MAN_SCALE")
		
		col = self.layout.column(align=True)
		col.template_list("UI_List_Scale","dummy",ob, "ee_p_scale", ob, "ee_p_colors_index",rows=1,maxrows=10,type='DEFAULT')
		op = col.operator("object.ee_add_new_pscale",text="Add new Scale Value", icon='ZOOMIN')
		op.scale = bpy.context.active_object.ee_p_scale[len(bpy.context.active_object.ee_p_scale)-1].scale
		op.frame = bpy.context.active_object.ee_p_scale[len(bpy.context.active_object.ee_p_scale)-1].frame+1
		
		row = self.layout.row()
		row = self.layout.row()
		row.label(text="Speed",icon="MAN_TRANS")
		
		col = self.layout.column(align=False)
		col.prop(ob,"ee_random_movement",text="Random Movement",slider=True)
		col.prop(ob,"ee_random_speed",text="Random Speed",slider=True)
		
		
		col = self.layout.column(align=True)
		col.template_list("UI_List_Speed","dummy",ob, "ee_p_speed", ob, "ee_p_colors_index",rows=1,maxrows=10,type='DEFAULT')
		op = col.operator("object.ee_add_new_pspeed",text="Add new Speed Value", icon='ZOOMIN')
		op.speed = bpy.context.active_object.ee_p_speed[len(bpy.context.active_object.ee_p_speed)-1].speed
		op.frame = bpy.context.active_object.ee_p_speed[len(bpy.context.active_object.ee_p_speed)-1].frame+1
		
		row = self.layout.row()
		row.prop(ob,"ee_explode",text="New Emitter on Particle Death")
		if ob.ee_explode:
			row = self.layout.row(align=True)
			row.prop(ob,"ee_explode_emitter",text="Emitter Name")
			row.prop_menu_enum(ob,"ee_explode_emitter_enum",text="",icon="OBJECT_DATAMODE")

### Custom template_list look
class UI_List_Proxy(bpy.types.UIList):
	def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
		ob = data
		slot = item
		col = layout.row(align=True)
		#myIcon = layout.icon(bpy.data.images[item.name+".png"])
		myIcon = layout.icon(bpy.data.textures[item.name+"_shadeless"])
		col.label(text="",icon_value=myIcon)
		col.prop(item,'name',text="",emboss=False)
		col2 = col.row()
		col2.enabled=False
		col2.prop(item,'mode',text="")
		
		tex = context.texture
		
		
		op = col.operator("object.ee_edit_pproxy",text="", icon='SCRIPTWIN')
		op.idx = index
		op.icon_idx = myIcon
		op = col.operator("object.ee_remove_latest_pproxy",text="", icon='X')
		op.idx = index


### Custom template_list look
class UI_List_Color(bpy.types.UIList):
	def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
		ob = data
		slot = item
		col = layout.row(align=True)
		col.column().prop(item,'color',text='')  
		
		#col = layout.row(align=True)
		col.prop(item,'frame',text="") 
		
		op = col.operator("object.ee_move_color",text="",icon="TRIA_DOWN")
		op.idx = index
		op.direction="down"
		
		op = col.operator("object.ee_move_color",text="",icon="TRIA_UP")
		op.idx = index
		op.direction="up" 
		
		op = col.operator("object.ee_remove_latest_pcolor",text="", icon='X',emboss=True)
		op.idx = index
		
### Custom template_list look
class UI_List_Scale(bpy.types.UIList):
	def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
		ob = data
		slot = item
		col = layout.row(align=True)
		col.prop(item,'scale',text='')  
		col.prop(item,'frame',text="") 
		
		op = col.operator("object.ee_move_scale",text="",icon="TRIA_DOWN")
		op.idx = index
		op.direction="down"
		
		op = col.operator("object.ee_move_scale",text="",icon="TRIA_UP")
		op.idx = index
		op.direction="up" 
		
		op = col.operator("object.ee_remove_latest_pscale",text="", icon='X',emboss=True)
		op.idx = index

### Custom template_list look for speed
class UI_List_Speed(bpy.types.UIList):
	def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
		ob = data
		slot = item
		col = layout.row(align=True)
		col.prop(item,'speed',text='')  
		col.prop(item,'frame',text="") 
		
		op = col.operator("object.ee_move_speed",text="",icon="TRIA_DOWN")
		op.idx = index
		op.direction="down"
		
		op = col.operator("object.ee_move_speed",text="",icon="TRIA_UP")
		op.idx = index
		op.direction="up" 
		
		op = col.operator("object.ee_remove_latest_pspeed",text="", icon='X',emboss=True)
		op.idx = index	  

### particle colorslist -> saves colors and frame where colors should change	
class ee_p_colors(bpy.types.PropertyGroup):
	def update_values(self, context):
		bpy.ops.object.ee_apply_values()
		
		### Slider Managemant: Slider can push themself
		ob = context.active_object
		for i,item in enumerate(ob.ee_p_colors):
			if self.frame == ob.ee_p_colors[i].frame:
				if i < len(ob.ee_p_colors)-1:
					if ob.ee_p_colors[i].frame >= ob.ee_p_colors[i+1].frame:
						ob.ee_p_colors[i+1].frame = ob.ee_p_colors[i].frame + 1
				

				if i > 0:
					if ob.ee_p_colors[i].frame <= ob.ee_p_colors[i-1].frame:
						ob.ee_p_colors[i-1].frame = ob.ee_p_colors[i].frame - 1
	
	color = FloatVectorProperty(name='color', description='Particle Color', default=(1.0, 0.0, 1.0, 1.0), min=0, max=1, step=1, precision=3, subtype='COLOR_GAMMA', size=4,update=update_values)
	frame = IntProperty(name='frame',default=0,min=0,max=100,update=update_values,subtype="FACTOR")

### particle scalelist -> saves scales and frame where scales should change 
class ee_p_scale(bpy.types.PropertyGroup):
	def update_values(self, context):
		bpy.ops.object.ee_apply_values()
		
		### Slider Managemant: Slider can push themself
		ob = context.active_object
		for i,item in enumerate(ob.ee_p_scale):
			if self.frame == ob.ee_p_scale[i].frame:
				if i < len(ob.ee_p_scale)-1:
					if ob.ee_p_scale[i].frame >= ob.ee_p_scale[i+1].frame:
						ob.ee_p_scale[i+1].frame = ob.ee_p_scale[i].frame + 1
				

				if i > 0:
					if ob.ee_p_scale[i].frame <= ob.ee_p_scale[i-1].frame:
						ob.ee_p_scale[i-1].frame = ob.ee_p_scale[i].frame - 1
						
	scale = FloatProperty(name='scale', description='Particle Scale', default=1.0, min=0,update=update_values)
	frame = IntProperty(name='frame',default=0,min=0,max=100,update=update_values,subtype="FACTOR")

### particle speedlist -> saves speeds and frame where speeds should change 
class ee_p_speed(bpy.types.PropertyGroup):
	def update_values(self, context):
		bpy.ops.object.ee_apply_values()
		
		### Slider Managemant: Slider can push themself
		ob = context.active_object
		for i,item in enumerate(ob.ee_p_speed):
			if self.frame == ob.ee_p_speed[i].frame:
				if i < len(ob.ee_p_speed)-1:
					if ob.ee_p_speed[i].frame >= ob.ee_p_speed[i+1].frame:
						ob.ee_p_speed[i+1].frame = ob.ee_p_speed[i].frame + 1
				

				if i > 0:
					if ob.ee_p_speed[i].frame <= ob.ee_p_speed[i-1].frame:
						ob.ee_p_speed[i-1].frame = ob.ee_p_speed[i].frame - 1
						
	
	speed = FloatProperty(name='speed', description='Particle Speed', default=0.1,precision=2,update=update_values)
	frame = IntProperty(name='frame',default=0,min=0,max=100,update=update_values,subtype="FACTOR")

### particle speedlist -> saves speeds and frame where speeds should change 
class ee_p_proxies(bpy.types.PropertyGroup):
	def update_values(self, context):
		bpy.ops.object.ee_apply_values()
	
	name = StringProperty(update=update_values)
	halo = BoolProperty(default=True,update=update_values)
	mode = EnumProperty(items=(("ADD","ADD","ADD"),("SHADELESS","SHADELESS","SHADELESS"),("SHADED","SHADED","SHADED")),update=update_values)
	

### Operator for editing existing Particle
class editPProxy(bpy.types.Operator):
	bl_idname = "object.ee_edit_pproxy"
	bl_label = "Edit Settings"
	
	icon_idx = IntProperty()
	
	def enum_items(self,context):
		PARTICLELIST = []
		i = 0
		
		for object in bpy.context.scene.objects:
			if object.ee_particle and "_add" in object.name:
				i+=1
				name = object.name.partition("_add")[0]
				PARTICLELIST.append((name,name,name,"OBJECT_DATAMODE",i))
		return PARTICLELIST
	
	idx = IntProperty()
	particles = EnumProperty(name="Particle",items=enum_items)
	halo = BoolProperty()
	
	
	def draw(self, context):
		layout = self.layout
		row = layout.row()
		row.prop(self, "particles")
		row = layout.row()
		row.prop(context.active_object.ee_p_proxies[self.idx], "mode",text="Blend mode")
		#row = layout.row()
		#row.prop(self, "halo")
		
		toolsettings = context.tool_settings.image_paint
		brush = toolsettings.brush
		col = self.layout.column()
		#col.template_ID_preview(brush, "texture",rows=3, cols=8)

	
	def invoke(self, context, event):
		wm = context.window_manager 
		ob = context.active_object
		try:
			self.particles = ob.ee_p_proxies[self.idx].name
		except:
			self.particles = self.particles 
		self.halo = ob.ee_p_proxies[self.idx].halo
		return wm.invoke_props_dialog(self)
	
	def execute(self,context):
		ob = context.active_object
		ob.ee_p_proxies[self.idx].name = self.particles
		ob.ee_p_proxies[self.idx].halo = self.halo
		return{'FINISHED'}

 
### Operator for adding new Particle Proxies	 
class addNewPProxy(bpy.types.Operator):
	bl_idname = "object.ee_add_new_pproxy" 
	bl_label = "Add new Particle"	
	
	def enum_items(self,context):
		PARTICLELIST = []
		i = 0
		for object in bpy.context.scene.objects:
			if object.ee_particle and "_add" in object.name:
				i+=1
				name = object.name.partition("_add")[0]
				PARTICLELIST.append((name,name,name,"OBJECT_DATAMODE",i))
		return PARTICLELIST
	
	
	particles = EnumProperty(name="Particle",items=enum_items)
	mode = EnumProperty(items=(("ADD","ADD","ADD"),("SHADELESS","SHADELESS","SHADELESS"),("SHADED","SHADED","SHADED")))
	
	
	
	def invoke(self, context, event):
		wm = context.window_manager 
		ob = context.active_object
		self.particles = self.particles
		
		
		return wm.invoke_props_dialog(self)
	
	def execute(self, context):
		particle = bpy.context.active_object.ee_p_proxies.add()
		particle.name = self.particles
		particle.halo = True
		particle.mode = self.mode
		bpy.ops.object.ee_apply_values()		
		return{'FINISHED'}
 
 
### Operator for adding new Colors to colorlist 
class addNewPColor(bpy.types.Operator):
	bl_idname = "object.ee_add_new_pcolor" 
	bl_label = ""	
	
	color = FloatVectorProperty(size=4,subtype="COLOR")
	frame = IntProperty(default=0)
	def execute(self, context):
		frames = []
		colors = bpy.context.active_object.ee_p_colors
		for item in colors:
			frames.append(item.frame)
			
		color = bpy.context.active_object.ee_p_colors.add()
		if len(bpy.context.active_object.ee_p_colors)>1:
			color.color = self.color#mathutils.Vector(bpy.context.active_object.ee_p_colors[len(bpy.context.active_object.ee_p_colors)-2].color)
			color.frame = self.frame#bpy.context.active_object.ee_p_colors[len(bpy.context.active_object.ee_p_colors)-2].frame+1
		else:
			color.color = self.color
		
		for i,item in enumerate(colors):
			if i < len(colors)-1:
				item.frame = frames[i]
		
		bpy.ops.object.ee_apply_values()		
		return{'FINISHED'}
	
### Operator for adding new Colors to colorlist 
class addNewPScale(bpy.types.Operator):
	bl_idname = "object.ee_add_new_pscale" 
	bl_label = ""	
	
	scale = FloatProperty(default=1.0)
	frame = IntProperty(default=0)
	
	def execute(self, context):
		frames = []
		scales = bpy.context.active_object.ee_p_scale
		for item in scales:
			frames.append(item.frame)
	
		scale = bpy.context.active_object.ee_p_scale.add()
		if len(bpy.context.active_object.ee_p_scale)>1:
			scale.scale = self.scale#bpy.context.active_object.ee_p_scale[len(bpy.context.active_object.ee_p_scale)-2].scale
			scale.frame = self.frame#bpy.context.active_object.ee_p_scale[len(bpy.context.active_object.ee_p_scale)-2].frame+1
		else:
			scale.scale = self.scale
			
		for i,item in enumerate(scales):
			if i < len(scales)-1:
				item.frame = frames[i]
		
		bpy.ops.object.ee_apply_values()		
		return{'FINISHED'}  
	
### Operator for adding new Colors to colorlist 
class addNewPSpeed(bpy.types.Operator):
	bl_idname = "object.ee_add_new_pspeed" 
	bl_label = ""	
	
	speed = FloatProperty(default=.1)
	frame = IntProperty(default=0)
	
	def execute(self, context):
		frames = []
		speeds = bpy.context.active_object.ee_p_speed
		for item in speeds:
			frames.append(item.frame)
	
		speed = bpy.context.active_object.ee_p_speed.add()
		if len(bpy.context.active_object.ee_p_speed)>1:
			speed.speed = self.speed#bpy.context.active_object.ee_p_speed[len(bpy.context.active_object.ee_p_speed)-2].speed
			speed.frame = self.frame#bpy.context.active_object.ee_p_speed[len(bpy.context.active_object.ee_p_speed)-2].frame+1
			
		for i,item in enumerate(speeds):
			if i < len(speeds)-1:
				item.frame = frames[i]	
			
		bpy.ops.object.ee_apply_values()		
		return{'FINISHED'}	  

### Operator for removing Colors from colorlist
class removePColor(bpy.types.Operator):
	bl_idname = "object.ee_remove_latest_pcolor" 
	bl_label = ""	   
	
	idx = IntProperty()
	
	def execute(self, context):
		ob = context.active_object
		if len(ob.ee_p_colors) > 1:
			bpy.context.active_object.ee_p_colors.remove(self.idx)  
			bpy.ops.object.ee_apply_values()
		else:
			self.report({'INFO'},'One Color is needed!')	
		return{'FINISHED'}  

### Operator for removing Scale from scalelist
class removePProxy(bpy.types.Operator):
	bl_idname = "object.ee_remove_latest_pproxy" 
	bl_label = ""	   
	
	idx = IntProperty()
	
	def execute(self, context):
		ob = context.active_object
		if len(ob.ee_p_proxies) > 1:
			bpy.context.active_object.ee_p_proxies.remove(self.idx)  
			bpy.ops.object.ee_apply_values()
		else:
			self.report({'INFO'},'One proxy is needed!')	
		return{'FINISHED'} 
	
### Operator for removing Scale from scalelist
class removePScale(bpy.types.Operator):
	bl_idname = "object.ee_remove_latest_pscale" 
	bl_label = ""	   
	
	idx = IntProperty()
	
	def execute(self, context):
		ob = context.active_object
		if len(ob.ee_p_scale) > 1:
			bpy.context.active_object.ee_p_scale.remove(self.idx)  
			bpy.ops.object.ee_apply_values()
		else:
			self.report({'INFO'},'One Scale is needed!')	
		return{'FINISHED'} 
	
### Operator for removing Speed from speedlist
class removePSpeed(bpy.types.Operator):
	bl_idname = "object.ee_remove_latest_pspeed" 
	bl_label = ""	   
	
	idx = IntProperty()
	
	def execute(self, context):
		ob = context.active_object
		if len(ob.ee_p_speed) > 1:
			bpy.context.active_object.ee_p_speed.remove(self.idx)  
			bpy.ops.object.ee_apply_values()
		else:
			self.report({'INFO'},'One Speed is needed!')	
		return{'FINISHED'}		  

### Change order of Colors in colorlist
class MoveColor(bpy.types.Operator):
	bl_idname = "object.ee_move_color"
	bl_label = "Move Color"
	bl_description = ""
	
	idx = IntProperty(default=0)
	direction = StringProperty(default="")
	
	def execute(self, context):
		ob = bpy.context.active_object
		if self.direction == 'down':
			ob.ee_p_colors.move(self.idx,self.idx+1)
		elif self.direction == 'up':
			ob.ee_p_colors.move(self.idx,self.idx-1)
		return{'FINISHED'}
	
### Change order of Colors in colorlist
class MoveScale(bpy.types.Operator):
	bl_idname = "object.ee_move_scale"
	bl_label = "Move Scale"
	bl_description = ""
	
	idx = IntProperty(default=0)
	direction = StringProperty(default="")
	
	def execute(self, context):
		ob = bpy.context.active_object
		if self.direction == 'down':
			ob.ee_p_scale.move(self.idx,self.idx+1)
		elif self.direction == 'up':
			ob.ee_p_scale.move(self.idx,self.idx-1)
		return{'FINISHED'}
	
### Change order of Colors in colorlist
class MoveSpeed(bpy.types.Operator):
	bl_label = "Move Speed"
	bl_idname = "object.ee_move_speed"
	bl_description = ""
	
	idx = IntProperty(default=0)
	direction = StringProperty(default="")
	
	def execute(self, context):
		ob = bpy.context.active_object
		if self.direction == 'down':
			ob.ee_p_speed.move(self.idx,self.idx+1)
		elif self.direction == 'up':
			ob.ee_p_speed.move(self.idx,self.idx-1)
		return{'FINISHED'}
	
	
### Add new Particle to particlelist
class ParticleToList(bpy.types.Operator):
	bl_label = "Particle to particle list"
	bl_idname = "object.ee_particle_to_list"
	bl_description = ""
	
	
	def execute(self, context):
		ob = bpy.context.active_object
		ob.ee_particle = True
		return{'FINISHED'}		  

### Update Operator that is called to apply all bpy properties to gameengine properties
class applyValues(bpy.types.Operator):
	bl_idname = "object.ee_apply_values" 
	bl_label = ""
	
	def createAction(self):
		ob = bpy.context.active_object
		actions = bpy.data.actions
		if ob.name not in actions:
			action = actions.new(ob.name)
			
				
	def createFCurve(self):
		ob = bpy.context.active_object
		ob.animation_data_create()
		ob.animation_data.action = bpy.data.actions[ob.name]
		
		### frame offset for animation
		frameOffset = 1000
		
		### remove fcurves before adding new
		for i in range(7):
			try:
				bpy.data.actions[ob.name].fcurves.remove(bpy.data.actions[ob.name].fcurves[0])
			except:
				pass
		
		### generate fcurves for color and scaling
		for i in range(4):
			bpy.data.actions[ob.name].fcurves.new("color",i)	
		for i in range(3):
			bpy.data.actions[ob.name].fcurves.new("scale",i)	
		
		### fcurves for particle colors
		for j,color in enumerate(ob.ee_p_colors):
			for i in range(4):
				factor = (color.frame/100)
				fps = 24/60
				frame = ((ob.ee_lifetime*factor))*fps
				key = bpy.data.actions[ob.name].fcurves[i].keyframe_points.insert(frame+frameOffset,color.color[i])
				key.interpolation = "LINEAR"

		### default object scale 
		for i in range(2):
			for j in range(3):
				fps = 24/60
				
				key = bpy.data.actions[ob.name].fcurves[j+4].keyframe_points.insert(i*frameOffset-1,ob.ee_emission_range[j]+.5) 
				key.interpolation = "LINEAR"
		
		### fcurves for particle scaling
		for j, scale in enumerate(ob.ee_p_scale):
			for i in range(3):
				factor = (scale.frame/100)
				fps = 24/60
				frame = ((ob.ee_lifetime*factor))*fps
				key = bpy.data.actions[ob.name].fcurves[i+4].keyframe_points.insert(frame+frameOffset,scale.scale)
				key.interpolation = "LINEAR"
		
	
	
	def setProperty(self,name,type,value):
		properties = bpy.context.object.game.properties
		if name not in properties:
			bpy.ops.object.game_property_new()
			properties['prop'].name = name
			properties[name].type = type
		properties[name].value = value
		
	
	def execute(self, context):
		bpy.ops.scene.ee_init_particles()
		
		ob = context.active_object
		
		### rename Action to emitter name
		if ob.name != ob.ee_name:
			if ob.ee_name in bpy.data.actions and ob.ee_name not in bpy.context.scene.objects:
				bpy.data.actions[ob.ee_name].name = ob.name
			ob.ee_name = ob.name
			
	
		
		### Create Action and Curves for ColorCalculation
		self.createAction()
		self.createFCurve()
		
		### Update Game Properties
		self.setProperty("ee_refresh_rate","INT",ob.ee_refresh_rate)
		self.setProperty("ee_amount","INT",ob.ee_amount)
		self.setProperty("ee_emission_rate","INT",ob.ee_emission_rate)
		self.setProperty("ee_lifetime","INT",ob.ee_lifetime)
		self.setProperty("ee_gravity","FLOAT",ob.ee_gravity)
		self.setProperty("ee_halo","BOOL",ob.ee_halo)
		self.setProperty("ee_emission_range_x","FLOAT",ob.ee_emission_range[0])
		self.setProperty("ee_emission_range_y","FLOAT",ob.ee_emission_range[1])
		self.setProperty("ee_emission_range_z","FLOAT",ob.ee_emission_range[2])
		
		self.setProperty("ee_emission_angle_x","FLOAT",ob.ee_emission_angle[0]/2)
		self.setProperty("ee_emission_angle_y","FLOAT",ob.ee_emission_angle[1]/2)
		self.setProperty("ee_rotation","FLOAT",ob.ee_rotation)
		self.setProperty("ee_random_orientation","BOOL",ob.ee_random_orientation)
		self.setProperty("ee_random_movement","FLOAT",ob.ee_random_movement)
		self.setProperty("ee_random_speed","FLOAT",ob.ee_random_speed)
		self.setProperty("ee_explode","BOOL",ob.ee_explode)
		self.setProperty("ee_explode_emitter","STRING",ob.ee_explode_emitter)
		
		settings = str([ob.ee_culling_on,ob.ee_culling_radius])
		self.setProperty("ee_frustum_culling","STRING",settings)
		self.setProperty("ee_freeze_mode","STRING",ob.ee_freeze_mode)
		
		speedlist = []
		for speed in ob.ee_p_speed:
			speedlist.append([round(speed.speed,2),speed.frame/100])
		self.setProperty("ee_speed","STRING",str(speedlist))
		
		proxylist = []
		for proxy in ob.ee_p_proxies:
			if proxy.mode == "ADD":
				suffix = "_add"
			if proxy.mode == "SHADELESS":
				suffix = "_shadeless"
			if proxy.mode == "SHADED":
				suffix = "_shaded"	  
			proxylist.append(proxy.name+suffix)
		self.setProperty("ee_proxies","STRING",str(proxylist))	  

		return{'FINISHED'}
	
		
		
	
class eeCreateParticleSystem(bpy.types.Operator):
	bl_idname = "object.ee_generate_particle_system" 
	bl_label = "easyEmit 2.0 - Generate System"
	bl_description = "Generate New Particle System"
	
	### generate Logic for the emitter object   
	def gen_particle_logic(self,context,name,pulse_mode,module_name,startUpScript):
		ob = context.active_object
		
		bpy.ops.logic.sensor_add(type='DELAY', name="", object="")
		ob.game.sensors[len(ob.game.sensors)-1].name = name
		ob.game.sensors[name].frequency = 0
		ob.game.sensors[name].use_pulse_true_level = pulse_mode
		ob.game.sensors[name].show_expanded = False
		
		bpy.ops.logic.controller_add(type='PYTHON', name="", object="")
		ob.game.controllers[len(ob.game.controllers)-1].name = name
		ob.game.controllers[name].mode = 'MODULE'
		ob.game.controllers[name].module = module_name
		ob.game.controllers[name].link(ob.game.sensors[name])
		ob.game.controllers[name].show_expanded = False
		ob.game.controllers[name].use_priority = startUpScript
		
		ob.game.physics_type = 'NO_COLLISION'
	
	def gen_emitter_mat(self,name,ob):
		if name not in bpy.data.materials:
			material = bpy.data.materials.new(name)
			material.diffuse_color = (1,1,1)
			material.type = "WIRE"
		else:
			material = bpy.data.materials[name] 
		
		ob.data.materials.append(material)
		ob.draw_type = "WIRE"
		
	def execute(self, context):
		ob = context.active_object
		
		### generate default material set to wire
		self.gen_emitter_mat("ee_emitter",ob)
		ob.hide_render = True
		ob.ee_emitter = True
		ob.ee_emission_rate = 20
		ob.ee_freeze_mode = "Pause"
		### generate logic bricks for the emitter. nedded for python execution
		self.gen_particle_logic(context,'ee_init',False,'particleEngine.init',True)
		self.gen_particle_logic(context,'ee_update',True,'particleEngine.update',False)
		
		### apply default values for the particle emitter
		bpy.ops.object.ee_add_new_pcolor(color=(1.0, 0.82, 0.0, 0.0),frame=0)
		bpy.ops.object.ee_add_new_pcolor(color=(1.0, 0.82, 0.0, 1.0),frame=1)
		bpy.ops.object.ee_add_new_pcolor(color=(1.0, 0.17, 0.0, 0.7),frame=44)
		bpy.ops.object.ee_add_new_pcolor(color=(1.0, 0.0, 0.0, 0.0),frame=100)
		try:
			bpy.ops.object.ee_add_new_pproxy(particles="particle_hard",mode="SHADELESS")
		except:
			bpy.ops.object.ee_add_new_pproxy(mode="SHADELESS")
		bpy.ops.object.ee_add_new_pscale(scale=0.0,frame=0)
		bpy.ops.object.ee_add_new_pscale(scale=0.5,frame=10)
		bpy.ops.object.ee_add_new_pscale(scale=0.8,frame=100)
		bpy.ops.object.ee_add_new_pspeed(speed=0.1,frame=0)
		bpy.ops.object.ee_add_new_pspeed(speed=0.05,frame=100)
		bpy.ops.object.ee_apply_values()
		return{'FINISHED'}  

class init_default_particles(bpy.types.Operator):
	bl_idname = "scene.ee_init_particles"
	bl_label = "Init default particles"
	
	offset = IntProperty(default=0)
	
	### load particleEngine.py
	def loadScript(self,scriptName):
		scriptPath = bpy.utils.script_paths("addons/easyEmit2")
		file = scriptPath[0] + '/'+scriptName
		bpy.ops.text.open(filepath=file, filter_blender=False, filter_image=False, filter_movie=False, filter_python=True, filter_font=False, filter_sound=False, filter_text=True, filter_btx=False, filter_collada=False, filter_folder=True, filemode=9, internal=True)
	
	def changeLayer(self,ob):
		### put object on last layer
		ob.layers[19] = True
		for i,layer in enumerate(ob.layers):
			if i != 19:
				ob.layers[i] = False
				
	def createParticle(self,name="",path="",use_shadeless=True,suffix="",y=0,z=0):

		### create particle plane
		bpy.ops.mesh.primitive_plane_add(view_align=False, enter_editmode=False, location=(0, 0, 0), rotation=(0, 0, 0), layers=(bpy.context.scene.layers[0],bpy.context.scene.layers[1],bpy.context.scene.layers[2],bpy.context.scene.layers[3],bpy.context.scene.layers[4],bpy.context.scene.layers[5],bpy.context.scene.layers[6],bpy.context.scene.layers[7],bpy.context.scene.layers[8],bpy.context.scene.layers[9],bpy.context.scene.layers[10],bpy.context.scene.layers[11],bpy.context.scene.layers[12],bpy.context.scene.layers[13],bpy.context.scene.layers[14],bpy.context.scene.layers[15],bpy.context.scene.layers[16],bpy.context.scene.layers[17],bpy.context.scene.layers[18],bpy.context.scene.layers[19]))
		ob = bpy.context.active_object
		ob.location = [0,(y+self.offset)*2,z]
		
		bpy.ops.object.mode_set(mode = 'EDIT')
		bpy.ops.mesh.flip_normals()
		bpy.ops.object.mode_set(mode = 'OBJECT')
		ob.game.physics_type = 'NO_COLLISION'
		ob.name = name
		ob.data.name = name
		bpy.ops.object.mode_set(mode = 'EDIT')
		bpy.ops.transform.rotate(value=-1.5708, axis=(0, 1, 0), constraint_axis=(False, True, False), constraint_orientation='GLOBAL', mirror=False, proportional='DISABLED', proportional_edit_falloff='SMOOTH', proportional_size=1, snap=False, snap_target='CLOSEST', snap_point=(0, 0, 0), snap_align=False, snap_normal=(0, 0, 0), release_confirm=False)
		bpy.ops.uv.unwrap(method='ANGLE_BASED', fill_holes=True, correct_aspect=True)
		bpy.ops.object.mode_set(mode = 'OBJECT')
	
		### create material
		material = bpy.data.materials.new(name)
		material.game_settings.use_backface_culling = True
		material.specular_intensity = 0
		
		if suffix == "_add":
			material.diffuse_color = (0,0,0)
			material.game_settings.alpha_blend = "ADD"		  
			material.use_shadeless = True
			material.use_mist = False

		elif suffix == "_shadeless":	
			material.diffuse_color = (1,1,1)
			material.game_settings.alpha_blend = "OPAQUE"		   
			material.use_shadeless = True

		elif suffix == "_shaded":
			material.diffuse_color = (1,1,1)
			material.game_settings.alpha_blend = "OPAQUE"  
			material.use_shadeless = False
			
		material.use_transparency = True
		material.alpha = 0.0
		material.use_object_color = True
		ob.data.materials.append(material)
		
		### load bitmap from addons folder
		basename = os.path.basename(path)
		if basename not in bpy.data.images:
			loadedBitmap = bpy.data.images.load(path)
		else:
			loadedBitmap =bpy.data.images[basename]  
		loadedBitmap.pack()
		loadedBitmap.use_alpha = True
		
		### create new texture with loaded bitmap
		if basename not in bpy.data.textures:
			texture = bpy.data.textures.new(name, type="IMAGE")
		else:
			texture = bpy.data.textures[basename]   
		#texture.image = bpy.data.images['particle_hard.png']
		texture.image = loadedBitmap
		
		### create new texture slot in material with created texture
		materialSlot = material.texture_slots.add()
		materialSlot.texture = texture
		if suffix == "_add":
			materialSlot.use_stencil = True
		materialSlot.use_map_alpha = True
		materialSlot.texture_coords = 'UV'
		
		ob.ee_particle = True
		
		self.changeLayer(ob)
		
		for vert in ob.data.vertices:
			vert.co[1] *= (loadedBitmap.size[0]/loadedBitmap.size[1])
		
		ob.select = False
		

		
		return ob
	
	def allObjects(self):
		OBJECTS = []
		for scene in bpy.data.scenes:
			for ob in scene.objects:
				OBJECTS.append(ob.name)
		return OBJECTS	  
		
	def addParticles(self,suffix="",OBJECTS=[],z=0):
		
		path = bpy.utils.script_paths("addons/easyEmit2/images")[0]
		folder = os.listdir(path)
		for i,file in enumerate(folder):
			if '.png' in file:
				name = file.partition(".")[0]+suffix
				### if particle is not in objectlist create particle
				if name not in OBJECTS:
					
					ob = self.createParticle(path=os.path.join(path,file),name=name,suffix=suffix,y=i,z=z)
					
					for scene in bpy.data.scenes:
						if name not in scene.objects:
							### particles get moved to last layer
							LAYERS = []
							for layer in scene.layers:
								LAYERS.append(layer)
							scene.layers[19] = True
							for i,layer in enumerate(scene.layers):
								if i != 19:
									scene.layers[i] = False
							
							scene.objects.link(ob) 
							self.changeLayer(ob)
							
							for i,layer in enumerate(scene.layers):
								scene.layers[i] = LAYERS[i]
				### if particle is not in scene link it to scene.
				else:
					for scene in bpy.data.scenes:
						if name not in scene.objects:
							### particles get moved to last layer
							LAYERS = []
							for layer in scene.layers:
								LAYERS.append(layer)
							scene.layers[19] = True
							for i,layer in enumerate(scene.layers):
								if i != 19:
									scene.layers[i] = False
							
							scene.objects.link(bpy.data.objects[name])
							
							for i,layer in enumerate(scene.layers):
								scene.layers[i] = LAYERS[i]
		
	def execute(self,context):
		for object in bpy.context.scene.objects:
			if object.ee_particle == True and "_add" in object.name:
				self.offset += 1
		
		OBJECTS = self.allObjects()
		
		### load particleEngine.py
		scriptName = "particleEngine.py"
		if scriptName not in bpy.data.texts:
			self.loadScript(scriptName)
		
		active_ob = bpy.context.active_object
		### create all particles that are located in the images folder
		self.addParticles(suffix="_add",OBJECTS=OBJECTS,z=0)
		self.addParticles(suffix="_shadeless",OBJECTS=OBJECTS,z=2)
		self.addParticles(suffix="_shaded",OBJECTS=OBJECTS,z=4)
		
		
		### create particle parent object
		if 'particleParent' not in OBJECTS:
			bpy.ops.object.empty_add(type='PLAIN_AXES', view_align=False, location=(0,0,0), rotation=(0, 0, 0), layers=(bpy.context.scene.layers[0],bpy.context.scene.layers[1],bpy.context.scene.layers[2],bpy.context.scene.layers[3],bpy.context.scene.layers[4],bpy.context.scene.layers[5],bpy.context.scene.layers[6],bpy.context.scene.layers[7],bpy.context.scene.layers[8],bpy.context.scene.layers[9],bpy.context.scene.layers[10],bpy.context.scene.layers[11],bpy.context.scene.layers[12],bpy.context.scene.layers[13],bpy.context.scene.layers[14],bpy.context.scene.layers[15],bpy.context.scene.layers[16],bpy.context.scene.layers[17],bpy.context.scene.layers[18],bpy.context.scene.layers[19]))
			ob = bpy.context.active_object
			ob.name = 'particleParent'
			self.changeLayer(ob)
			ob.select = False
		else:
			ob = bpy.data.objects['particleParent']
			for scene in bpy.data.scenes:
				if ob.name not in scene.objects:
					### particles get moved to last layer
					LAYERS = []
					for layer in scene.layers:
						LAYERS.append(layer)
					scene.layers[19] = True
					for i,layer in enumerate(scene.layers):
						if i != 19:
							scene.layers[i] = False
					scene.objects.link(ob)
					
					for i,layer in enumerate(scene.layers):
						scene.layers[i] = LAYERS[i]
		
		### select object that was active before						
		bpy.context.scene.objects.active = active_ob  
		if active_ob != None:
			active_ob.select = True				 
		return{'FINISHED'}		  





def register():
	bpy.utils.register_class(easyEmitUISettings)
	bpy.utils.register_class(easyEmitUIAdd)	   
	bpy.utils.register_class(ee_p_colors)   
	bpy.utils.register_class(ee_p_scale)		
	bpy.utils.register_class(ee_p_speed)		
	bpy.utils.register_class(ee_p_proxies)	   
	bpy.utils.register_class(addNewPColor)  
	bpy.utils.register_class(addNewPScale)  
	bpy.utils.register_class(addNewPSpeed)  
	bpy.utils.register_class(addNewPProxy)  
	bpy.utils.register_class(editPProxy)		 
	bpy.utils.register_class(removePColor)  
	bpy.utils.register_class(removePScale)  
	bpy.utils.register_class(removePSpeed)  
	bpy.utils.register_class(removePProxy)  
	bpy.utils.register_class(applyValues) 
	bpy.utils.register_class(UI_List_Proxy)  
	bpy.utils.register_class(UI_List_Color)  
	bpy.utils.register_class(UI_List_Scale)  
	bpy.utils.register_class(UI_List_Speed)  
	bpy.utils.register_class(MoveColor) 
	bpy.utils.register_class(MoveScale) 
	bpy.utils.register_class(MoveSpeed) 
	bpy.utils.register_class(eeCreateParticleSystem) 
	bpy.utils.register_class(init_default_particles)
	
	bpy.utils.register_class(ParticleToList) 
	
	bpy.types.Object.ee_p_colors = CollectionProperty(type=ee_p_colors)
	bpy.types.Object.ee_p_scale = CollectionProperty(type=ee_p_scale)
	bpy.types.Object.ee_p_speed = CollectionProperty(type=ee_p_speed)
	bpy.types.Object.ee_p_colors_index = IntProperty(default=-1,max=-1)
	
	
	bpy.types.Object.ee_p_proxies = CollectionProperty(type=ee_p_proxies)
	


def unregister():
	bpy.utils.unregister_class(easyEmitUISettings)
	bpy.utils.unregister_class(easyEmitUIAdd)		 
	bpy.utils.unregister_class(ee_p_colors) 
	bpy.utils.unregister_class(ee_p_scale)	  
	bpy.utils.unregister_class(ee_p_speed)	  
	bpy.utils.unregister_class(ee_p_proxies)		 
	bpy.utils.unregister_class(addNewPColor)	
	bpy.utils.unregister_class(addNewPScale)	
	bpy.utils.unregister_class(addNewPSpeed)	
	bpy.utils.unregister_class(addNewPProxy)	
	bpy.utils.unregister_class(editPProxy)	   
	bpy.utils.unregister_class(removePColor)	
	bpy.utils.unregister_class(removePScale)	
	bpy.utils.unregister_class(removePSpeed)	
	bpy.utils.unregister_class(removePProxy)
	bpy.utils.unregister_class(applyValues) 
	bpy.utils.unregister_class(UI_List_Proxy)  
	bpy.utils.unregister_class(UI_List_Color)  
	bpy.utils.unregister_class(UI_List_Scale)  
	bpy.utils.unregister_class(UI_List_Speed)  
	bpy.utils.unregister_class(MoveColor) 
	bpy.utils.unregister_class(MoveScale) 
	bpy.utils.unregister_class(MoveSpeed) 
	bpy.utils.unregister_class(eeCreateParticleSystem) 
	bpy.utils.unregister_class(init_default_particles) 
	
	bpy.utils.unregister_class(ParticleToList) 
	
		
if __name__ == "__main__":
	register()